package com.yiqixuejava.reconciliation.service.impl;

import com.yiqixuejava.reconciliation.dto.RDetail;
import com.yiqixuejava.reconciliation.entity.SourceEntity;
import com.yiqixuejava.reconciliation.exception.ServiceException;
import com.yiqixuejava.reconciliation.service.ReconService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import java.io.*;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import static com.yiqixuejava.reconciliation.exception.CoreExceptionEnum.FILE_NOT_EXIST;
import static com.yiqixuejava.reconciliation.exception.CoreExceptionEnum.FILE_PARSE_FAILED;

/**
 * 类的描述：银联ACOMN解析服务
 *
 * @author: huxp
 * @createDate: 2019/11/11 15:50
 * @version: v1.0
 */
@Service("ACOMN")
@Scope("prototype")
public class ACOMNReconService implements ReconService {
    private static final String regex = "[D][1-2]";
    private static final String ymfTk = "[T][T]";
    private Logger log = LoggerFactory.getLogger(getClass());
    /**
     * 一条记录的长度
     */
    public static final int ITEM_LEN = 951;
    /**
     * 每个字段[域]的长度
     */
    public static final int[] itemLens = {0,
            12, 12, 7, 11, 20, 13, 13, 13, 5, 7,
            5, 9, 16, 13, 3, 7, 12, 7, 3, 4,
            13, 13, 13, 2, 4, 2, 2, 11, 12, 2,
            3, 3, 13, 15, 20, 3, 41, 5, 3, 2, 20, 11,
            7, 2, 41, 46};

    /**
     * 每个字段[域]的位置
     */
    public static int[] itemLocations = new int[itemLens.length];

    /**
     * 文件读取流
     */
    protected FileInputStream fis;
    /**
     * 文件读取流
     */
    private InputStreamReader isr = null;
    /**
     * 文件读取流
     */
    private BufferedReader br = null;

    static {
        //根据每个字段的长度计算每个字段的位置
        for (int i = 1; i < itemLens.length; i++) {
            int loc = 0;
            for (int j = 1; j < i; j++) {
                loc += itemLens[j];
            }
            itemLocations[i] = loc;
        }
    }

    @Override
    public void prepare(SourceEntity sourceEntity) throws ServiceException {
        try {
            File file = new File(sourceEntity.getUri());
            fis = new FileInputStream(file);
            isr = new InputStreamReader(fis, "ASCII");
            br = new BufferedReader(isr);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(FILE_NOT_EXIST);
        }
    }

    /**
     * @return
     * @throws IOException
     */
    private String readNextText() throws IOException {
        String line = br.readLine();
        if ("".equals(line) || line == null || line.length() != 500) {
            return null;
        }
        String buf = line.substring(0, 363);//acomn文件除前364个字符有用其他均无用
        return buf;
    }

    /**
     * 数据域截取
     *
     * @param itemIndex 域号
     * @param rowData   数据源
     * @return
     */
    private String getItemFromRow(int itemIndex, String rowData) {
        try {
            String ret = rowData.substring(itemLocations[itemIndex], itemLocations[itemIndex] + itemLens[itemIndex] - 1);//每个数据后都有一空格作为数据分割线
            return ret;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    @Override
    public List<RDetail> getNextData(int maxSize) throws ServiceException {
        try {
            List<RDetail> rDetails = null;
            //获取一行
            String rowData = "";
            while ((rowData = readNextText()) != null) {
                //從字符串中獲取一些需要使用的域
                String ACOMN_1_orgId = getItemFromRow(1, rowData).trim();
                String ACOMN_2_sendId = getItemFromRow(2, rowData).trim();
                String ACOMN_3_sysNo = getItemFromRow(3, rowData).trim();
                String ACOMN_4_Trade_Time = getItemFromRow(4, rowData);
                String ACOMN_6_Trade_Amount = getItemFromRow(6, rowData);
                String ACOMN_5_Pan = getItemFromRow(5, rowData).trim();
                String ACOMN_12_posSn = getItemFromRow(12, rowData);
                String ACOMN_13_merchantCode = getItemFromRow(13, rowData);
                String ACOMN_37_trxNo = getItemFromRow(37, rowData).trim();
                if (null == ACOMN_37_trxNo) {
                    continue;
                } else {
                    String index = ACOMN_37_trxNo.substring(0, 2);
                    if (!(index.matches(regex))) {
                        //一码付云闪付入库
                        if (index.matches(ymfTk)) {
                            //如果为一码付云闪付，机具号就是订单号
                            ACOMN_12_posSn = ACOMN_37_trxNo;
                            StringBuffer stringBuffer = new StringBuffer();
                            stringBuffer.append(ACOMN_1_orgId)
                                    .append(ACOMN_2_sendId)
                                    .append(ACOMN_3_sysNo)
                                    .append(ACOMN_4_Trade_Time.trim());
                            ACOMN_37_trxNo = stringBuffer.toString();
                        } else {
                            continue;
                        }
                    }

                }
                String ACOMN_8_Fee = getItemFromRow(8, rowData);

                String ACOMN_9_messageType = getItemFromRow(9, rowData);
                String ACOMN_10_tradeType = getItemFromRow(10, rowData);
                String ACOMN_11_Mcc = getItemFromRow(11, rowData);

                String ACOMN_21_slfYsJhf = getItemFromRow(21, rowData);
                String ACOMN_22_slfYfJhf = getItemFromRow(22, rowData);
                String ACOMN_23_zjQsf = getItemFromRow(23, rowData);
                String ACOMN_19_tradeCode = getItemFromRow(19, rowData);
                BigDecimal amount = new BigDecimal(ACOMN_6_Trade_Amount);
                BigDecimal fee = new BigDecimal(ACOMN_8_Fee.substring(1));
                RDetail rDetail = new RDetail();
                rDetail.setOrderNo(ACOMN_37_trxNo);
                //金额为分，直接取整
                rDetail.setTradeAmount(amount.setScale(0, BigDecimal.ROUND_DOWN).toPlainString());
                rDetail.setTradeDateTime(guessTradeTime(ACOMN_4_Trade_Time));
                if (null == rDetails) {
                    rDetails = new ArrayList<>();
                }
                rDetails.add(rDetail);
                if (rDetails.size() >= maxSize) {
                    return rDetails;
                }
            }
            return rDetails;
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(FILE_PARSE_FAILED);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new ServiceException(FILE_PARSE_FAILED);
        }
    }

    /**
     * 猜测交易时间（由于报文里面的交易时间没有年份，所以需要根据当前年份进行猜测）
     *
     * @param tradeTimeFromRecord 报文中的交易时间(MMddHHmmss)
     * @return 猜测的交易时间(yyyy - MM - dd HH : mm : ss)
     */
    private String guessTradeTime(String tradeTimeFromRecord) throws ParseException {
        //利用输入的时间(MMddHHmmss)与当前年份拼装成猜测的交易时间
        String guessDateString = getCurrentYear() + tradeTimeFromRecord;
        DateFormat inputDf = new SimpleDateFormat("yyyyMMddHHmmss");
        DateFormat outputDf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //第一次猜测的交易时间
        Date guessDate = inputDf.parse(guessDateString);
        //当前时间
        Date currentDate = new Date();
        //如果猜测的交易时间晚于当前时间，说明是去年的交易
        if (guessDate.after(currentDate)) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(currentDate);
            int year = calendar.get(Calendar.YEAR) - 1;
            calendar.set(Calendar.YEAR, year);
            guessDate = calendar.getTime();
        }
        return outputDf.format(guessDate);
    }

    private String getCurrentYear() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        return sdf.format(new Date());
    }

    @Override
    public void destroy() {
        if (isr != null) {
            try {
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            isr = null;
        }
    }
}